package com.study.chunguard.common.validation;

import com.study.chunguard.common.exception.BusinessException;
import org.hibernate.validator.HibernateValidator;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.study.chunguard.common.exception.code.ResponseCode.FAIL;

/**
 * 参数校验工具类,用于校验对象的属性是否符合规范,作为 spring mvc 参数校验的补充
 *
 * @author zhaowenhao
 * @since 2024-07-19
 */
public class ValidateUtils {

    public static final String NULL_MSG = "参数缺失";

    private ValidateUtils() {
        throw new IllegalStateException("Utility class");
    }

    public static final Validator validator;

    static {
        try (ValidatorFactory validatorFactory = Validation
                .byProvider(HibernateValidator.class)
                .configure()
                .buildValidatorFactory()) {
            validator = validatorFactory.getValidator();
        }
    }

    /**
     * 静态方法校验使用的，如果校验失败则抛出异常
     */
    public static void validate(Object object) {
        validate(object, null);
    }

    /**
     * 静态方法校验使用，并且带分组的，如果校验失败则抛出异常
     */
    public static <T> void validate(Object object, Class<T> group) {
        if (object == null) {
            throw new BusinessException(FAIL.getCode(), NULL_MSG);
        }
        Set<ConstraintViolation<Object>> violations;
        if (group == null) {
            violations = validator.validate(object);
        } else {
            violations = validator.validate(object, group);
        }
        processViolations(violations);
    }

    /**
     * 校验对象并返回错误信息列表，如果校验通过则返回空列表
     */
    public static List<String> getErrors(Object object) {
        return getErrors(object, null);
    }

    /**
     * 带分组的校验对象并返回错误信息列表，如果校验通过则返回空列表
     */
    public static <T> List<String> getErrors(Object object, Class<T> group) {
        if (object == null) {
            return Collections.singletonList(NULL_MSG);
        }
        Set<ConstraintViolation<Object>> violations;
        if (group == null) {
            violations = validator.validate(object);
        } else {
            violations = validator.validate(object, group);
        }
        return generateErrorMessages(violations);
    }

    /**
     * 校验对象并返回是否校验通过的布尔值
     */
    public static boolean isValid(Object object) {
        return isValid(object, null);
    }

    /**
     * 带分组的校验对象并返回是否校验通过的布尔值
     */
    public static <T> boolean isValid(Object object, Class<T> group) {
        if (object == null) {
            return false;
        }
        Set<ConstraintViolation<Object>> violations;
        if (group == null) {
            violations = validator.validate(object);
        } else {
            violations = validator.validate(object, group);
        }
        return violations.isEmpty();
    }

    private static void processViolations(Set<ConstraintViolation<Object>> violations) {
        if (!violations.isEmpty()) {
            String errorMessage = String.join(", ", generateErrorMessages(violations));
            throw new BusinessException(FAIL.getCode(), errorMessage);
        }
    }

    private static List<String> generateErrorMessages(Set<ConstraintViolation<Object>> violations) {
        return violations.stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.toList());
    }
}
